/*
 * File     : StructureFactory.java
 * Created  : 1 May 2011
 *
 * Copyright © 2011 Matthew Wilson (mj. {my-surname} .uk {at} gmail.com)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.googlecode.dni.type.structure;

import com.googlecode.dni.DirectNativeInterface;
import com.googlecode.dni.type.Freeable;
import com.googlecode.dni.type.LifetimeManagedList;
import com.googlecode.dni.type.LifetimeManagedObject;
import com.googlecode.dni.type.NativeObjectList;
import com.googlecode.dni.type.Pointer;
import com.googlecode.dni.type.cenum.CEnumUnknownValue;

/**
 * Provides an abstract factory for a structure type.
 *
 * @param <T>
 *            the type of structure
 *
 * @author Matthew Wilson
 */
public interface StructureFactory< T extends Structure >
{

    /**
     * <p>
     *  Creates a new instance.
     * </p>
     * <p>
     *  All fields will be initialised to their defaults.  All numeric values
     *  will be zero; all boolean values will be false; all enums will be the
     *  value corresponding to zero (or <code>null</code> or the
     *  {@linkplain CEnumUnknownValue unknown value} if zero is undefined); all
     *  pointers will be null.
     * </p>
     * <p>
     *  Note that creating a structure requires allocating native memory.
     *  Allocating native memory is (usually) orders of magnitude slower than
     *  allocating a Java object.  Furthermore, unless the structure extends
     *  {@link LifetimeManagedObject}, the Java object has to be registered with
     *  a finalizer hook (or equivalent), slowing down the Java object creation
     *  too.
     * </p>
     *
     * @return a new instance
     *
     * @see DirectNativeInterface#getStructureFactory(Class)
     *
     * @throws UnsupportedOperationException
     *             if the structure is
     *             {@linkplain StructureOptions#opaque() opaque}
     */
    T allocate();

    /**
     * <p>
     *  Creates a new instance wrapping a pointer.
     * </p>
     * <p>
     *  This method does not allocate any memory, and the created structure will
     *  not automatically free the memory when finalized (if the structure does
     *  not extends {@link LifetimeManagedObject}).
     * </p>
     * <p>
     *  Insofar as can be reasonably expected, DNI attempts to return the same
     *  structure instance for the same pointer when the structure does not
     *  extend {@link LifetimeManagedObject} and was created through
     *  {@link #allocate()}.
     * </p>
     *
     * @param pointer
     *            the pointer
     *
     * @return a structure
     *
     * @throws NullPointerException
     *             if the pointer is null
     */
    T fromPointer( Pointer pointer );

    /**
     * <p>
     *  Creates a new list of structures with the given size.
     * </p>
     * <p>
     *  The structures are arranged in memory one immediately after another;
     *  this behaviour matches the C type
     *  <code>struct&nbsp;<i>t</i>&nbsp;x[<i>size</i>]</code>.  The returned
     *  list is immutable (although the contained structures are themselves
     *  mutable).
     * </p>
     * <p>
     *  If the structure typed extends {@link LifetimeManagedObject}, the
     *  {@link Freeable#free()} method <em>must not be called</em> on the
     *  structures themselves; this is akin to attempting to free an array
     *  element in C.  (It will likely crash the VM.)
     * </p>
     * <p>
     *  The returned list's native memory will be freed when the list is
     *  collected by the garbage collector.
     * </p>
     *
     * @param size
     *            the number of items in the list; zero or greater
     *
     * @return a list
     */
    NativeObjectList< T > allocateList( int size );

    /**
     * <p>
     *  Creates a new list of structures with the given size using the memory at
     *  the given pointer.
     * </p>
     * <p>
     *  See the notes on {@link #allocateList(int)} for details of the list.
     * </p>
     * <p>
     *  The returned list's native memory will not be automatically freed.
     * </p>
     *
     * @param pointer
     *            the pointer to the first element
     * @param size
     *            the number of items in the list; zero or greater
     *
     * @return a list
     */
    NativeObjectList< T > listFromPointer( Pointer pointer, int size );

    /**
     * <p>
     *  Creates a new list of structures with the given size.
     * </p>
     * <p>
     *  See the notes on {@link #allocateList(int)} for details of the list.
     * </p>
     * <p>
     *  The returned list's native memory will only be freed when the
     *  {@link Freeable#free()} method is called <em>on the list itself</em>.
     * </p>
     *
     * @param size
     *            the number of items in the list; zero or greater
     *
     * @return a list
     */
    LifetimeManagedList< T > allocateLifetimeManagedList( int size );

    /**
     * <p>
     *  Creates a new list of structures with the given size using the memory at
     *  the given pointer.
     * </p>
     * <p>
     *  See the notes on {@link #allocateList(int)} for details of the list.
     * </p>
     * <p>
     *  The returned list's native memory will only be freed when the
     *  {@link Freeable#free()} method is called <em>on the list itself</em>.
     * </p>
     *
     * @param pointer
     *            the pointer to the first element
     * @param size
     *            the number of items in the list; zero or greater
     *
     * @return a list
     */
    LifetimeManagedList< T > lifetimeManagedListFromPointer( Pointer pointer, int size );

}
